<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // #region
        // 这种写法haha会被提升
        // haha();
        // // 函数声明
        // function haha() {
        //     console.log("this is haha")
        // }
        // #endregion


        // #region

        // xiaoxin();  //即便使用函数原本的xiaoxin也无法访问，所以这是函数表达式和函数声明的区别（只要不是function直接开头的都是不是函数声明）
        // xiaoxinfun();   //这里应该会报错TypeError，因为还不知道xiaoxinfun是一个函数
        // // 先声明xiaoxinfun，执行到这里的时候定义xiaoxin函数，并将其引用给xiaoxinfun
        // var xiaoxinfun = function xiaoxin() {
        //     console.log("this is xiaoxin")
        //     console.log(xiaoxin)    // 在内部可以调用xiaoxin查看其内容
        // }

        // xiaoxinfun();
        // console.log(xiaoxin)    // 访问失败，ReferenceError，找不到xiaoxin
        // xiaoxin();      // 这个已经执行不了了，xiaoxin已经被销毁，而其内容被赋值给了xiaoxinfun

        // #endregion
        
        
        /*
            具名函数表达式的函数名只在函数内部有效，在函数外部就无效了。

            这样设计也很好理解：

                如果具名函数表达式的函数名全局有效的话，后边再有一个针对funcA的定义就会把之前定义的funcA覆盖掉，这样就直接改变了funcB的行为，显然不是我们想要的。
        */

        // #region
        // 那么如果是在自定义块作用域中进行函数声明，会被提升吗
        foo();  // TypeError: foo is not a function
        // 有趣的是，这里的报错是TypeError而不是ReferenceError，说明函数提升了，但没完全提升，相当于进行了 var foo;但未进行赋值
        /*
            在《你不知道的JavaScript》的41页中提到：
                一个普通块内部的函数声明通常会被提升到所在作用域的顶部，这也就是为什么上面调用foo的时候出现的是TypeError而不是ReferenceError了
                注意：
                    普通块包括：if,for,while等等，但不要忽略了随手可加的{}这个也是普通块，普通块的作用域是依托与外部的函数作用域的
        */
        {
            function foo(){
                console.log("this is foo")
            }
        }
        foo();  // "this is foo"
        // 在块作用域中的函数声明不会被提升
        // #endregion
    </script>
</body>

</html>